package com.vhans.db.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vhans.core.domain.AAdmin;
import com.vhans.core.redis.RedisService;
import com.vhans.core.utils.SecurityUtils;
import com.vhans.core.utils.StringUtils;
import com.vhans.core.web.model.dto.MailDTO;
import com.vhans.db.mapper.AAdminMapper;
import com.vhans.db.model.dto.login.LoginDTO;
import com.vhans.db.model.dto.login.UpdatePasswdDTO;
import com.vhans.db.service.IALoginService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

import static com.vhans.core.constant.CommonConstant.CAPTCHA;
import static com.vhans.core.constant.MqConstant.EMAIL_EXCHANGE;
import static com.vhans.core.constant.MqConstant.EMAIL_SIMPLE_KEY;
import static com.vhans.core.constant.RedisConstant.CODE_EXPIRE_TIME;
import static com.vhans.core.constant.RedisConstant.CODE_KEY_P;

/**
 * 后台登录业务接口实现类
 *
 * @author vhans
 **/
@Service
public class ALoginServiceImpl implements IALoginService {

    @Autowired
    private AAdminMapper adminMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisService redisService;

    @Override
    public String loginAdmin(LoginDTO login) {
        AAdmin admin = adminMapper.selectOne(new LambdaQueryWrapper<AAdmin>()
                .select(AAdmin::getId)
                .eq(AAdmin::getAdminName, login.getUsername())
                .eq(AAdmin::getPassword, SecurityUtils.sha256Encrypt(login.getPassword())));
        Assert.notNull(admin, "管理员不存在或密码错误");
        // 校验指定账号是否已被封禁，如果被封禁则抛出异常 `DisableServiceException`
        StpUtil.checkDisable(admin.getId());
        // 通过校验后，再进行登录
        StpUtil.login(admin.getId());
        return StpUtil.getTokenValue();
    }

    @Override
    public void sendCode(String admin) {
        AAdmin adminInfo = adminMapper.selectOne(new LambdaQueryWrapper<AAdmin>()
                .select(AAdmin::getEmail)
                .eq(AAdmin::getAdminName, admin));
        Assert.isFalse(StringUtils.isNull(adminInfo), "不存在管理员信息: " + admin);
        RandomGenerator randomGenerator = new RandomGenerator("0123456789", 6);
        String code = randomGenerator.generate();
        MailDTO mailDTO = MailDTO.builder()
                .toEmail(adminInfo.getEmail())
                .subject(CAPTCHA)
                .content("您的验证码为 " + code + " 有效期为" + CODE_EXPIRE_TIME + "分钟")
                .build();
        // 验证码存入消息队列
        rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, EMAIL_SIMPLE_KEY, mailDTO);
        // 验证码存入redis
        redisService.setObject(CODE_KEY_P + admin, code, CODE_EXPIRE_TIME, TimeUnit.MINUTES);
    }

    @Override
    public void updatePasswd(UpdatePasswdDTO passwdDTO) {
        verifyCode(passwdDTO.getUsername(), passwdDTO.getCode());
        // 查询管理员id
        Integer adminId = adminMapper.selectOne(new LambdaQueryWrapper<AAdmin>()
                .select(AAdmin::getId)
                .eq(AAdmin::getAdminName, passwdDTO.getUsername())).getId();
        // 更新密码
        adminMapper.updateById(AAdmin.builder()
                .password(SecurityUtils.sha256Encrypt(passwdDTO.getPassword()))
                .id(adminId).build());
    }

    /**
     * 校验密码更新验证码
     *
     * @param adminName 账号
     * @param code      验证码
     */
    public void verifyCode(String adminName, String code) {
        String sysCode = redisService.getObject(CODE_KEY_P + adminName);
        Assert.notBlank(sysCode, "验证码未发送或已过期!");
        Assert.isTrue(sysCode.equals(code), "验证码错误，请重新输入!");
    }
}